package top.truehaku.generator.code.application.assembler;

import org.springframework.util.CollectionUtils;
import top.truehaku.generator.code.application.command.CodeGroup;
import top.truehaku.generator.code.application.vo.*;
import top.truehaku.generator.code.domain.model.code.*;
import top.truehaku.generator.code.domain.model.table.Table;
import top.truehaku.generator.starter.GlobalCodeProperties;

import java.util.*;
import java.util.stream.Collectors;

public class CodeAssembler {

    public static List<Code> toCode(CodeGroup codeGroup, GlobalCodeProperties globalCodeProperties,String entityName) {
        Map<String,Code> codeMap = new HashMap<>();
        List<Code> codeList = codeGroup.getCodes().stream().map(targetCode ->
                {
                    Code code = new Code(
                            new CodeId(targetCode.getIdentity())
                            , new CodeDirectory(globalCodeProperties.getProjectRootPath(), targetCode.getSubProject(), globalCodeProperties.getProjectPackage(), targetCode.getModule(), targetCode.getRelativePath())
                            , new CodeFile(targetCode.getPrefix(), entityName, targetCode.getSuffix(), targetCode.getExtension())
                            , new CodeProperty(targetCode.isOverridable(), targetCode.isWhetherPojo(), targetCode.getImports())
                            , new CodeTemplate(targetCode.getTemplatePath())
                    );
                    if (targetCode.getParentId() != null) {
                        Code parent = codeMap.get(targetCode.getParentId());
                        code.setParent(parent);
                    }
                    if (!CollectionUtils.isEmpty(targetCode.getDependIds())){
                        List<Code> depends = new ArrayList<>();
                        for (String id:targetCode.getDependIds()) {
                            Code dependCode = codeMap.get(id);
                            if (dependCode != null) {
                                depends.add(dependCode);
                            }
                        }
                        code.setDepends(depends);
                    }
                    codeMap.put(targetCode.getIdentity(),code);
                    return code;
                }
        ).collect(Collectors.toList());
        return codeList;
    }

    public static Variable toVariable(Code code, Table table){
        TableInfo tableInfo = TableInfo.builder()
                .name(table.getTableId().getTableName())
                .scheme(table.getTableId().getTableScheme())
                .alias(table.getTableAlias())
                .comment(table.getTableComment().getTableComment())
                .module(table.getModuleName())
                .lastname(table.getLastname())
                .containsUnique(table.containsUnique())
                .containsCombineColumn(table.containsCombineColumn())
                .build();
        List<FieldInfo> fields= table.getColumnList().stream().map(column -> {
            FieldInfo field = FieldInfo.builder()
                    .type(column.getColumnType().getJavaType().getSimpleName())
                    .name(column.getFieldName())
                    .capitalizeName(column.getFieldCapitalizeName())
                    .parentIncluded(column.getParentIncluded())
                    .isCondition(column.getColumnComment().isCondition())
                    .condition(column.getColumnComment().getCondition())
                    .isCombine(column.getColumnComment().isCombine())
                    .column(ColumnInfo.builder()
                            .name(column.getColumnId().getColumnName())
                            .type(column.getColumnType().getSimpleType())
                            .comment(column.getColumnComment().getComment())
                            .nullable(column.getNullable())
                            .primaryKey(column.getPrimaryKey())
                            .autoIncrement(column.getAutoIncrement())
                            .ordinalPosition(column.getOrdinalPosition())
                            .uniqueKey(column.getUniqueKey())
                            .remark(column.getColumnComment().getRemark())
                            .isCombine(column.getColumnComment().isCombine())
                            .build())
                    .build();
            if (column.getColumnComment().isCombine()){
                List<FieldInfo> combineFields= column.getCombineColumns().stream().map(item ->
                    FieldInfo.builder()
                            .type(item.getColumnType().getJavaType().getSimpleName())
                            .name(item.getFieldName())
                            .capitalizeName(item.getFieldCapitalizeName())
                            .parentIncluded(item.getParentIncluded())
                            .isCondition(item.getColumnComment().isCondition())
                            .condition(item.getColumnComment().getCondition())
                            .column(ColumnInfo.builder()
                                    .name(item.getColumnId().getColumnName())
                                    .type(item.getColumnType().getSimpleType())
                                    .comment(item.getColumnComment().getComment())
                                    .nullable(item.getNullable())
                                    .primaryKey(item.getPrimaryKey())
                                    .autoIncrement(item.getAutoIncrement())
                                    .ordinalPosition(item.getOrdinalPosition())
                                    .uniqueKey(item.getUniqueKey())
                                    .remark(item.getColumnComment().getRemark())
                                    .build())
                            .build()

                ).collect(Collectors.toList());
                field.setCombineFields(combineFields);
            }
            return field;

        }).collect(Collectors.toList());

        EntityInfo entityInfo = EntityInfo.builder()
                .entityName(table.getEntityName())
                .objectName(table.getObjectName())
                .table(tableInfo)
                .fields(fields)
                .primaryField(fields.stream().filter(field->field.getColumn().getPrimaryKey()).findFirst().get())
                .containsDate(table.containsDate())
                .containsString(table.containsString())
                .build();
        ClazzInfo clazzInfo = ClazzInfo.builder()
                .name(code.getFile().getSimpleName())
                .packageName(code.getDirectory().getPackage())
                .typeName(code.getTypeName())
                .build();
        Set<String> imports = new HashSet<>();
        imports.addAll(table.getImports(code.getCodeProperty().isWhetherPojo()));
        imports.addAll(code.getImports());
        clazzInfo.setImports(imports);
        Code parent = code.getParent();
        if (parent !=null){
            clazzInfo.setParent(ClazzInfo.builder()
                    .name(parent.getFile().getSimpleName())
                    .packageName(parent.getDirectory().getPackage())
                    .typeName(parent.getTypeName())
                    .build());
        }
        return Variable.builder()
                .createTime(new Date())
                .clazz(clazzInfo)
                .entity(entityInfo)
                .build();
    }

    public static Variable variableMapping(Code code, Table table){
        Variable variable = VariableMapper.instance.variable(code, table);
        Set<String> imports = new HashSet<>();
        imports.addAll(table.getImports(code.getCodeProperty().isWhetherPojo()));
        imports.addAll(code.getImports());
        variable.getClazz().setImports(imports);
        return variable;
    }

}
